
package nsga;

/**
 * Individuo Sistema de Caracterización Inteligende de Carga de Transformadores de Distribución
 * @author Gustavo Planás
 */

public class IndividuoSCICTD implements Cloneable, Individuo 
{

    private int[] nodos; // Un nodo es un Transformador con o sin medidor asociado.
                         // 0 = Nodo Transformador. 1 = Nodo Transformador con Medidor asociado.
    private int n; // Cantidad Total de Transformadores.
    private int k; // Cantidad Total de Medidores.
    private double[] fitness; // Fitness del Individuo.
    private double fitnessAlgoritmo; // Fitness del Individuo de acuerdo al Algoritmo.

    //
    // Método Contructor.
    //
    public IndividuoSCICTD(int n) 
    {
        this.n = n;
        this.k = 0;
        nodos = new int[this.n];
        for (int i = 0; i < this.n; i++) 
        {
            nodos[i] = 0;
        }
    }

    //
    // Completa el individuo en forma aleatoria.
    //
    public void createIndividuoAleatorio(int n)
    {
        for (int i = 0; i < n; i++) 
        {
            if (Math.random() < 0.5)
                nodos[i] = 0;
            else
            {
                nodos[i] = 1;
                k++;
            }
        }
        // PREGUNTAR SI ES CORRECTO MUTAR EN CASO DE QUE NINGUN TRAFO TENGA MEDIDOR.
        while(!isIndividuoValido())
            mutar();
    }
    
    //
    // Devuelve un individuo creado en forma aleatoria.
    //
    public static IndividuoSCICTD getIndividuoAleatorio(int n)
    {
        IndividuoSCICTD individuo = new IndividuoSCICTD(n);
        individuo.createIndividuoAleatorio(n);
        return individuo;
    }
    
    //
    // Devuelve el Vector de Nodos.
    //
    public int[] getNodos() 
    {
        return nodos.clone();
    }
    
    //
    // Agregar los nodos al Individuo (Se controla que sea válido).
    //
    public void setNodos(int[] nodos)
    {
        this.nodos = nodos;
        k = 0;
        for (int i = 0; i < n; i++) 
        {
            if (nodos[i] == 1)
                k++;
        }
        // PREGUNTAR SI ES CORRECTO MUTAR EN CASO DE QUE NINGUN TRAFO TENGA MEDIDOR.
        while(!isIndividuoValido())
            mutar();
    }

    //
    // Devuelve Fitness.
    //
    @Override
    public double[] getFitness() 
    {
        return fitness.clone();
    }

    //
    // Almacena el valor del Fitness.
    //
    @Override
    public void setFitness(double[] fitness) 
    {
        this.fitness = fitness;
    }

    //
    // Devuelve el Fitness del Algoritmo.
    //
    @Override
    public double getFitnessAlgoritmo() 
    {
        return fitnessAlgoritmo;
    }
       
    //
    // Almacena el Fitness del Algoritmo.
    //
    @Override
    public void setFitnessAlgoritmo(double fitnessAlgoritmo) 
    {
        this.fitnessAlgoritmo = fitnessAlgoritmo;
    }

    //
    // Devuelve la cantidad de medidores.
    //
    public int getK() 
    {
        return k;
    }
    
    //
    // Muta al Individuo.
    //
    @Override
    public void mutar() 
    {
        double mutarNodo = Math.random();
        double nodo = 1.0 / n;
        double d = 0;
        int i = -1;
        while(d <= mutarNodo)
        {
            d += nodo;
            i++;
        }
        if (nodos[i] == 1)
        {
            nodos[i] = 0;
            k--;
        } else
        {
            nodos[i] = 1;
            k++;
        }
        while(!isIndividuoValido())
            mutar();            
    }

    //
    // Devuelve una Copia del Individuo.
    //
    @Override
    public Individuo clone() 
    {
        IndividuoSCICTD individuoSCICTD = null;
        try {
            individuoSCICTD = (IndividuoSCICTD) super.clone();
        } catch (CloneNotSupportedException cloneNotSupportedException) {
        }
        individuoSCICTD.nodos = nodos.clone();
        individuoSCICTD.fitness = fitness.clone();
        return individuoSCICTD;
    }

    //
    // Controla que el Individuo sea válido.
    //
    public boolean isIndividuoValido() 
    {
        if (k == 0)
            return false;
        for (int i = 0; i < this.n; i++) 
        {
            if (nodos[i] != 0  && nodos[i] != 1)
                return false;
        }
        return true;
    }
}
